/* PDCurses */

#include <curspriv.h>

/*man-start**************************************************************

getstr
------

### Synopsis

    int getstr(char *str);
    int wgetstr(WINDOW *win, char *str);
    int mvgetstr(int y, int x, char *str);
    int mvwgetstr(WINDOW *win, int y, int x, char *str);
    int getnstr(char *str, int n);
    int wgetnstr(WINDOW *win, char *str, int n);
    int mvgetnstr(int y, int x, char *str, int n);
    int mvwgetnstr(WINDOW *win, int y, int x, char *str, int n);

    int get_wstr(wint_t *wstr);
    int wget_wstr(WINDOW *win, wint_t *wstr);
    int mvget_wstr(int y, int x, wint_t *wstr);
    int mvwget_wstr(WINDOW *win, int, int, wint_t *wstr);
    int getn_wstr(wint_t *wstr, int n);
    int wgetn_wstr(WINDOW *win, wint_t *wstr, int n);
    int mvgetn_wstr(int y, int x, wint_t *wstr, int n);
    int mvwgetn_wstr(WINDOW *win, int y, int x, wint_t *wstr, int n);

### Description

   These routines call wgetch() repeatedly to build a string,
   interpreting erase and kill characters along the way, until a newline
   or carriage return is received. When PDCurses is built with wide-
   character support enabled, the narrow-character functions convert the
   wgetch()'d values into a multibyte string in the current locale
   before returning it. The resulting string is placed in the area
   pointed to by *str. The routines with n as the last argument read at
   most n characters.

   Note that there's no way to know how long the buffer passed to
   wgetstr() is, so use wgetnstr() to avoid buffer overflows.

### Return Value

   These functions return ERR on failure or any other value on success.

### Portability
                             X/Open  ncurses  NetBSD
    getstr                      Y       Y       Y
    wgetstr                     Y       Y       Y
    mvgetstr                    Y       Y       Y
    mvwgetstr                   Y       Y       Y
    getnstr                     Y       Y       Y
    wgetnstr                    Y       Y       Y
    mvgetnstr                   Y       Y       Y
    mvwgetnstr                  Y       Y       Y
    get_wstr                    Y       Y       Y
    wget_wstr                   Y       Y       Y
    mvget_wstr                  Y       Y       Y
    mvwget_wstr                 Y       Y       Y
    getn_wstr                   Y       Y       Y
    wgetn_wstr                  Y       Y       Y
    mvgetn_wstr                 Y       Y       Y
    mvwgetn_wstr                Y       Y       Y

**man-end****************************************************************/

#define MAXLINE 255

int wgetnstr( WINDOW* win, char* str, int n )
{
#ifdef PDC_WIDE
	wchar_t wstr[MAXLINE + 1];
	wint_t wintstr[MAXLINE + 1];
	int i;

	if( n < 0 || n > MAXLINE )
	{
		n = MAXLINE;
	}

	if( wgetn_wstr( win, wintstr, n ) == ERR )
	{
		return ERR;
	}
	for( i = 0; i < n; ++i )
	{
		wstr[i] = ( wchar_t )wintstr[i];
	}

	return PDC_wcstombs( str, wstr, n );
#else
	int ch, i, num, x, chars;
	char* p;
	bool stop, oldecho, oldcbreak, oldnodelay;

	PDC_LOG( ( "wgetnstr() - called\n" ) );

	if( !win || !str )
	{
		return ERR;
	}

	chars = 0;
	p = str;
	stop = FALSE;

	x = win->_curx;

	oldcbreak = SP->cbreak; /* remember states */
	oldecho = SP->echo;
	oldnodelay = win->_nodelay;

	SP->echo = FALSE;       /* we do echo ourselves */
	cbreak();               /* ensure each key is returned immediately */
	win->_nodelay = FALSE;  /* don't return -1 */

	wrefresh( win );

	while( !stop )
	{
		ch = wgetch( win );

		switch( ch )
		{

			case '\t':
				ch = ' ';
				num = TABSIZE - ( win->_curx - x ) % TABSIZE;
				for( i = 0; i < num; i++ )
				{
					if( chars < n )
					{
						if( oldecho )
						{
							waddch( win, ch );
						}
						*p++ = ch;
						++chars;
					}
					else
					{
						beep();
					}
				}
				break;

			case _ECHAR:        /* CTRL-H -- Delete character */
				if( p > str )
				{
					if( oldecho )
					{
						waddstr( win, "\b \b" );
					}
					ch = ( unsigned char )( *--p );
					if( ( ch < ' ' ) && ( oldecho ) )
					{
						waddstr( win, "\b \b" );
					}
					chars--;
				}
				break;

			case _DLCHAR:       /* CTRL-U -- Delete line */
				while( p > str )
				{
					if( oldecho )
					{
						waddstr( win, "\b \b" );
					}
					ch = ( unsigned char )( *--p );
					if( ( ch < ' ' ) && ( oldecho ) )
					{
						waddstr( win, "\b \b" );
					}
				}
				chars = 0;
				break;

			case _DWCHAR:       /* CTRL-W -- Delete word */

				while( ( p > str ) && ( *( p - 1 ) == ' ' ) )
				{
					if( oldecho )
					{
						waddstr( win, "\b \b" );
					}

					--p;        /* remove space */
					chars--;
				}
				while( ( p > str ) && ( *( p - 1 ) != ' ' ) )
				{
					if( oldecho )
					{
						waddstr( win, "\b \b" );
					}

					ch = ( unsigned char )( *--p );
					if( ( ch < ' ' ) && ( oldecho ) )
					{
						waddstr( win, "\b \b" );
					}
					chars--;
				}
				break;

			case '\n':
			case '\r':
				stop = TRUE;
				if( oldecho )
				{
					waddch( win, '\n' );
				}
				break;

			default:
				if( chars < n )
				{
					if( !SP->key_code && ch < 0x100 )
					{
						*p++ = ch;
						if( oldecho )
						{
							waddch( win, ch );
						}
						chars++;
					}
				}
				else
				{
					beep();
				}

				break;

		}

		wrefresh( win );
	}

	*p = '\0';

	SP->echo = oldecho;     /* restore old settings */
	SP->cbreak = oldcbreak;
	win->_nodelay = oldnodelay;

	return OK;
#endif
}

int getstr( char* str )
{
	PDC_LOG( ( "getstr() - called\n" ) );

	return wgetnstr( stdscr, str, MAXLINE );
}

int wgetstr( WINDOW* win, char* str )
{
	PDC_LOG( ( "wgetstr() - called\n" ) );

	return wgetnstr( win, str, MAXLINE );
}

int mvgetstr( int y, int x, char* str )
{
	PDC_LOG( ( "mvgetstr() - called\n" ) );

	if( move( y, x ) == ERR )
	{
		return ERR;
	}

	return wgetnstr( stdscr, str, MAXLINE );
}

int mvwgetstr( WINDOW* win, int y, int x, char* str )
{
	PDC_LOG( ( "mvwgetstr() - called\n" ) );

	if( wmove( win, y, x ) == ERR )
	{
		return ERR;
	}

	return wgetnstr( win, str, MAXLINE );
}

int getnstr( char* str, int n )
{
	PDC_LOG( ( "getnstr() - called\n" ) );

	return wgetnstr( stdscr, str, n );
}

int mvgetnstr( int y, int x, char* str, int n )
{
	PDC_LOG( ( "mvgetnstr() - called\n" ) );

	if( move( y, x ) == ERR )
	{
		return ERR;
	}

	return wgetnstr( stdscr, str, n );
}

int mvwgetnstr( WINDOW* win, int y, int x, char* str, int n )
{
	PDC_LOG( ( "mvwgetnstr() - called\n" ) );

	if( wmove( win, y, x ) == ERR )
	{
		return ERR;
	}

	return wgetnstr( win, str, n );
}

#ifdef PDC_WIDE
int wgetn_wstr( WINDOW* win, wint_t* wstr, int n )
{
	int ch, i, num, x, chars;
	wint_t* p;
	bool stop, oldecho, oldcbreak, oldnodelay;

	PDC_LOG( ( "wgetn_wstr() - called\n" ) );

	if( !win || !wstr )
	{
		return ERR;
	}

	chars = 0;
	p = wstr;
	stop = FALSE;

	x = win->_curx;

	oldcbreak = SP->cbreak; /* remember states */
	oldecho = SP->echo;
	oldnodelay = win->_nodelay;

	SP->echo = FALSE;       /* we do echo ourselves */
	cbreak();               /* ensure each key is returned immediately */
	win->_nodelay = FALSE;  /* don't return -1 */

	wrefresh( win );

	while( !stop )
	{
		ch = wgetch( win );

		switch( ch )
		{

			case '\t':
				ch = ' ';
				num = TABSIZE - ( win->_curx - x ) % TABSIZE;
				for( i = 0; i < num; i++ )
				{
					if( chars < n )
					{
						if( oldecho )
						{
							waddch( win, ch );
						}
						*p++ = ch;
						++chars;
					}
					else
					{
						beep();
					}
				}
				break;

			case _ECHAR:        /* CTRL-H -- Delete character */
				if( p > wstr )
				{
					if( oldecho )
					{
						waddstr( win, "\b \b" );
					}
					ch = *--p;
					if( ( ch < ' ' ) && ( oldecho ) )
					{
						waddstr( win, "\b \b" );
					}
					chars--;
				}
				break;

			case _DLCHAR:       /* CTRL-U -- Delete line */
				while( p > wstr )
				{
					if( oldecho )
					{
						waddstr( win, "\b \b" );
					}
					ch = *--p;
					if( ( ch < ' ' ) && ( oldecho ) )
					{
						waddstr( win, "\b \b" );
					}
				}
				chars = 0;
				break;

			case _DWCHAR:       /* CTRL-W -- Delete word */

				while( ( p > wstr ) && ( *( p - 1 ) == ' ' ) )
				{
					if( oldecho )
					{
						waddstr( win, "\b \b" );
					}

					--p;        /* remove space */
					chars--;
				}
				while( ( p > wstr ) && ( *( p - 1 ) != ' ' ) )
				{
					if( oldecho )
					{
						waddstr( win, "\b \b" );
					}

					ch = *--p;
					if( ( ch < ' ' ) && ( oldecho ) )
					{
						waddstr( win, "\b \b" );
					}
					chars--;
				}
				break;

			case '\n':
			case '\r':
				stop = TRUE;
				if( oldecho )
				{
					waddch( win, '\n' );
				}
				break;

			default:
				if( chars < n )
				{
					if( !SP->key_code )
					{
						*p++ = ch;
						if( oldecho )
						{
							waddch( win, ch );
						}
						chars++;
					}
				}
				else
				{
					beep();
				}

				break;

		}

		wrefresh( win );
	}

	*p = '\0';

	SP->echo = oldecho;     /* restore old settings */
	SP->cbreak = oldcbreak;
	win->_nodelay = oldnodelay;

	return OK;
}

int get_wstr( wint_t* wstr )
{
	PDC_LOG( ( "get_wstr() - called\n" ) );

	return wgetn_wstr( stdscr, wstr, MAXLINE );
}

int wget_wstr( WINDOW* win, wint_t* wstr )
{
	PDC_LOG( ( "wget_wstr() - called\n" ) );

	return wgetn_wstr( win, wstr, MAXLINE );
}

int mvget_wstr( int y, int x, wint_t* wstr )
{
	PDC_LOG( ( "mvget_wstr() - called\n" ) );

	if( move( y, x ) == ERR )
	{
		return ERR;
	}

	return wgetn_wstr( stdscr, wstr, MAXLINE );
}

int mvwget_wstr( WINDOW* win, int y, int x, wint_t* wstr )
{
	PDC_LOG( ( "mvwget_wstr() - called\n" ) );

	if( wmove( win, y, x ) == ERR )
	{
		return ERR;
	}

	return wgetn_wstr( win, wstr, MAXLINE );
}

int getn_wstr( wint_t* wstr, int n )
{
	PDC_LOG( ( "getn_wstr() - called\n" ) );

	return wgetn_wstr( stdscr, wstr, n );
}

int mvgetn_wstr( int y, int x, wint_t* wstr, int n )
{
	PDC_LOG( ( "mvgetn_wstr() - called\n" ) );

	if( move( y, x ) == ERR )
	{
		return ERR;
	}

	return wgetn_wstr( stdscr, wstr, n );
}

int mvwgetn_wstr( WINDOW* win, int y, int x, wint_t* wstr, int n )
{
	PDC_LOG( ( "mvwgetn_wstr() - called\n" ) );

	if( wmove( win, y, x ) == ERR )
	{
		return ERR;
	}

	return wgetn_wstr( win, wstr, n );
}
#endif
